/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/**
 * Software License, Version 1.0
 *
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 *
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 *
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University.  For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering,
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 *
 *
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of
 * any other entity.  Indiana University disclaims any liability to any
 * recipient for claims brought by any other entity based on infringement of
 * intellectual property rights or otherwise.
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 *GENERATED USING SOFTWARE.
 */

package cgl.narada.wsinfra.deployment.axis.wse;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.xmlbeans.XmlCursor;

import cgl.narada.wsinfra.WsMessageFlow;
import cgl.narada.wsinfra.deployment.Filter;
import cgl.narada.wsinfra.deployment.SOAPContext;
import cgl.narada.wsinfra.deployment.SOAPContextFactory;
import cgl.narada.wsinfra.exception.DeploymentException;
import cgl.narada.wsinfra.exception.MessageFlowException;
import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.FromDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.util.SoapEnvelopeConversion;
import cgl.narada.wsinfra.util.SoapMessageAlteration;
import cgl.narada.wsinfra.util.SoapPrinter;
import cgl.narada.wsinfra.wsa.WsaEnvelopeCreator;
import cgl.narada.wsinfra.wsa.WsaEprCreator;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;
import cgl.narada.wsinfra.wse.WseNodeUtils;
import cgl.narada.wsinfra.wse.WseQNames;

/**
 * @author Damodar Yemme
 * Created on Mar 23, 2005
 * This class will help Source Client's or Endpoint's to send Notifications by calling Source Web Service running on Axis.
 */
public class WseSourceClientService
    implements WsMessageFlow {
  private String moduleName = "WseSourceClientService";
  private String sourceAddress;
  private String subManagerAddress;
  private WsaEprCreator wsaEprCreator;
  private WsaEnvelopeCreator wsaEnvelopeCreator;
  private SoapEnvelopeConversion soapEnvelopeConversion;
  private SoapMessageAlteration soapMessageAlteration;
  private WseQNames wseQNames;
  private SOAPContextFactory soapContextFactory;
  private int tracker;
  private WseNodeUtils wseNodeUtils;

  public WseSourceClientService(String sourceAddressParam,
                                String subManagerAddressParam) {
    sourceAddress = sourceAddressParam;
    subManagerAddress = subManagerAddressParam;
    wsaEprCreator = WsaProcessingFactory.getWsaEprCreator();
    wsaEnvelopeCreator = WsaProcessingFactory.getWsaEnvelopeCreator();

    soapEnvelopeConversion = SoapEnvelopeConversion.getInstance();
    soapMessageAlteration = SoapMessageAlteration.getInstance();
    soapContextFactory = SOAPContextFactory.getInstance();
    wseQNames = WseQNames.getInstance();
  }

  /**
   * Routes a message enroute to the application. The message is basically
   * routed to a neighboring filter which is nearer to the application.
   */
  public final void enrouteToApplication(SOAPMessage soapMessage) throws
      MessageFlowException {
  }

  /**
   * I over wrote this method because I have to make call to Sink instead of
   * Source. Sink will store request & response
   *
   * @param SOAPMessage
   */
  public final void enrouteToNetwork(SOAPMessage soapMessage) throws
      MessageFlowException {
    try {
      org.apache.axis.message.SOAPEnvelope senv = (org.apache.axis.message.
          SOAPEnvelope) soapMessage
          .getSOAPPart().getEnvelope();
      System.out.println(moduleName + " soapMessage \n**********\n" + senv);
      Service service = new Service();
      Call call = (Call) service.createCall();
      call.setTargetEndpointAddress(sourceAddress);
      call.setSOAPActionURI("processMessage");
      SOAPEnvelope env = (SOAPEnvelope) call.invoke(senv);
    }
    catch (Exception e) {
      System.out.println(moduleName + " Exception here " + e);
    }
  }

  public SOAPMessage createSOAPMessage() {

    EndpointReferenceType sourceEpr = wsaEprCreator.createEpr(sourceAddress);
    FromDocument from = FromDocument.Factory.newInstance();
    from.setFrom(sourceEpr);
    EnvelopeDocument envelopeDocument =
        wsaEnvelopeCreator.createSoapEnvelope(from);

    QName qname = new QName("http://www.naradabrokering.org",
                            "Application-Content");
    XmlCursor bodyCursor =
        envelopeDocument.getEnvelope().getBody().newCursor();
    tracker++;
    String value = "Tracker :" + tracker + "\n" +
        "The quick brown fox jumps upon the lazy dog";
    bodyCursor.toNextToken();

    String catUri = "http://www.naradabrokering.org/catalog";
    bodyCursor.insertElement("catalog", catUri);
    bodyCursor.toPrevToken();
    bodyCursor.insertElement("cd", catUri);
    bodyCursor.toPrevToken();
    bodyCursor.insertElementWithText("price", catUri, "11.90");

    String xpathString = "<catalog> <cd> <title>Hide your heart</title> <artist>Bonnie Tyler</artist>  <country>UK</country>  <company>CBS Records</company> <price>11.90</price>  <year>1988</year>  </cd>  </catalog>";
    //bodyCursor.insertChars(xpathString);
    bodyCursor.insertElementWithText(qname, value);
    bodyCursor.dispose();

    bodyCursor = envelopeDocument.getEnvelope().getBody().newCursor();
    //String poUri = "http://openuri.org/easypo";
    //bodyCursor.insertElement("purchase-order", poUri);
    //bodyCursor.toPrevToken();
    //bodyCursor.insertElement("line-item", poUri);

    addTopicInfo(envelopeDocument);

    //bodyCursor.toPrevToken();
    //bodyCursor.insertElementWithText("price", poUri, "300");
    //bodyCursor.dispose();

    /*
      EnvelopeDocument envelopeCopy=(EnvelopeDocument)envelopeDocument.copy();
      System.out.println(moduleName + "COPY OF THE EnvelopeDocument is \n" +
      envelopeCopy.toString());
     */

    SOAPMessage soapMessage = null;
    try {
      soapMessage = soapEnvelopeConversion.getSOAPMessage(envelopeDocument);
    }
    catch (ProcessingException ex) {
      String errorReport = "Problems converting to javax.xml.SOAPMessage\n"
          + ex.toString();
      System.out.println(errorReport);
    }

    return soapMessage;
  }

  public void addTopicInfo(EnvelopeDocument envelopeDocument) {
    String topicName = "/Literature/Shakespere";
    QName qName = wseQNames.getTopicQNameNBX();
    boolean added = soapMessageAlteration.addToSoapHeader(envelopeDocument,
        qName, topicName);

    if (!added) {
      System.out.println(moduleName + "Addition of Topic info NOT Successful");
    }
  }

  public void onMessage(SOAPMessage soapMessage) {
    System.out.println(moduleName + "Received SOAP Message from the " +
                       "underlying infrastructure");
    printSoapMessage(soapMessage);
  }

  public void onException(Exception exception) {

  }

  public void printSoapMessage(SOAPMessage soapMessage) {
    String soapMsg = null;
    try {
      soapMsg = SoapPrinter.getStringRepresentation(soapMessage);
    }
    catch (Exception e) {
      System.out.println(moduleName + "Problems printing SOAPMessage");
    }
    System.out.println(soapMsg);
  }

  public void sendSOAPMessage(SOAPMessage soapMessage) throws
      DeploymentException, MessageFlowException, ProcessingException {
    processMessageFromApplication(soapMessage);
  }

  /** Process a message received over the network. */
  public void processMessageFromNetwork(SOAPMessage soapMessage) {
    try {
      int position = 1;
      SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
      propagateMessageTowardsApplication(soapContext, position);
    }
    catch (DeploymentException de) {
      System.out.println(moduleName + de.toString() + "\n");
      de.printStackTrace();
    }
  }

  /** Injects a message based on the filter's position within the filter
      pipeline towards the application. */
  public void injectMessageTowardsApplication(SOAPMessage soapMessage,
                                              Filter filter) throws
      DeploymentException {
    boolean newAddition = false;

    /** We will start processing after this position. If the filter is
       injecting a message, we assume that this filter does not need to
       process this same message again. */
    int position = 2;
    position--;

    SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
    propagateMessageTowardsApplication(soapContext, position);
  }

  /** Injects a message at a specific location within the filter pipeline
      towards the application. */
  public void injectMessageTowardsApplication(SOAPMessage soapMessage,
                                              int position) throws
      DeploymentException {

    //checkPositionForProblems(position);
    SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
    propagateMessageTowardsApplication(soapContext, position);
  }

  /** This method propagates a message towards the network, starting at the
      <i>position</i> that has been specified, with decreasing values of the
      <i>position</i> moving the message closer to the application. */
  private void propagateMessageTowardsApplication(SOAPContext soapContext,
                                                  int position) {
    System.out.println(moduleName + "Propagating message towards application"
                       + ", position = " + position);
  }

  /** Process a message received from the application. */
  public void processMessageFromApplication(SOAPMessage soapMessage) throws
      DeploymentException, MessageFlowException, ProcessingException {
    int position = 0;
    SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
    propagateMessageTowardsNetwork(soapContext, position);
  }

  /** Injects a message at the filter immediately following this filter in
      the path TOWARDS the NETWORK. */
  public void injectMessageTowardsNetwork(SOAPMessage soapMessage,
                                          Filter filter) throws
      DeploymentException, MessageFlowException, ProcessingException {
    boolean newAddition = false;
    //checkFilterForProblems(filter, newAddition);

    /** We will start processing after this position. If the filter is
       injecting a message, we assume that this filter does not need to
       process this same message again. */
    int position = 1; // filterLinkedList.indexOf(filter);
    position++;
    SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
    propagateMessageTowardsNetwork(soapContext, position);

  }

  /** Injects a message at a specific location within the filter pipeline. */
  public void injectMessageTowardsNetwork(SOAPMessage soapMessage, int position) throws
      DeploymentException, MessageFlowException, ProcessingException {

    // checkPositionForProblems(position);
    SOAPContext soapContext = soapContextFactory.newSOAPContext(soapMessage);
    propagateMessageTowardsNetwork(soapContext, position);
  }

  /** This method propagates a message towards the network, starting at the
      <i>position</i> that has been specified, with increasing values of the
      <i>position</i> moving the message closer to the network. */
  private void propagateMessageTowardsNetwork(SOAPContext soapContext,
                                              int position) throws
      DeploymentException, MessageFlowException, ProcessingException {
    boolean continueProcessing = true;
    SOAPMessage soapMessage = soapContext.getSOAPMessage();
    //networkSubstrate.routeMessage(soapMessage);
    enrouteToNetwork(soapMessage);
  }
}